/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package net.octopeer.core;

import java.io.File;
import java.io.StringReader;

import java.util.ArrayList;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

import org.xml.sax.InputSource;

import net.octopeer.utilities.XMLTools;

/**
 *
 * @author andria
 */
public class Cache {
    private Resource resource;
    private ArrayList<PeerNode> nodeList;
    
    public Cache() {
        this.nodeList = new ArrayList<PeerNode>();
    }
    
    public Cache(Resource resource, PeerNode cacheNode) {
        this.resource = resource;
        this.nodeList = new ArrayList<PeerNode>();
        this.nodeList.add(cacheNode);
    }
    
    public Cache(Resource resource, ArrayList<PeerNode> cacheNodeList) {
        this.resource = resource;
        this.nodeList = cacheNodeList;
    }
    
    public void setResource(Resource resource) {
        this.resource = resource;
    }
    
    public void setNodeList(PeerNode cacheNode) {
        this.nodeList = new ArrayList<PeerNode>();
        this.nodeList.add(cacheNode);
    }
    
    public void setNodeList(ArrayList<PeerNode> cacheNodeList) {
        this.nodeList = cacheNodeList;
    }
    
    public boolean addNode(PeerNode cacheNode) {
        boolean success = false;
        
        int nodeIdx = findNodeIdx(cacheNode);
        if (nodeIdx == -1) {
            this.nodeList.add(cacheNode);
            success = true;
        }
        
        return success;
    }
    
    public boolean removeNode(PeerNode cacheNode) {
        boolean success = false;
        
        int nodeIdx = findNodeIdx(cacheNode);
        if (nodeIdx != -1) {
            this.nodeList.remove(cacheNode);
            success = true;
        }
        
        return success;
    }
    
    public int findNodeIdx(PeerNode cacheNode) {
        int cacheNodeIdx = -1;
        int loop = 0;
        PeerNode tempNode = null;
        
        while (loop < this.nodeList.size()) {
            tempNode = (PeerNode) this.nodeList.get(loop);
            
            if (tempNode.getNodeID().equals(cacheNode.getNodeID())) {
                cacheNodeIdx = loop;
            }
            
            loop++;
        }
        
        return cacheNodeIdx;
    }    
    
    public Resource getResource() {
        return this.resource;
    }
    
    public ArrayList<PeerNode> getNodeList() {
        return this.nodeList;
    }
    
    public Document toXMLDoc() throws Exception {
        Document doc;
        XMLTools xt = new XMLTools();        
        doc = xt.db.newDocument();
        
        Element rootEle = doc.createElement("Cache");

        // Resource
        Element cacheResourceEle = doc.createElement("Cache:Resource");
        
        // ID
        Element resourceIDEle = doc.createElement("Cache:Resource:ID");
        Text resourceIDText = doc.createTextNode(this.resource.getResourceID());
        resourceIDEle.appendChild(resourceIDText);
        cacheResourceEle.appendChild(resourceIDEle);        
        
        // IPaddress
        Element resourceTypeEle = doc.createElement("Cache:Resource:Type");
        Text resourceTypeText = doc.createTextNode(this.resource.getResourceType());
        resourceTypeEle.appendChild(resourceTypeText);
        cacheResourceEle.appendChild(resourceTypeEle);        
        
        // Port
        Element resourceDetailEle = doc.createElement("Cache:Resource:Detail");
        Text resourceDetailText = doc.createTextNode(this.resource.getResourceDetail());
        resourceDetailEle.appendChild(resourceDetailText);
        cacheResourceEle.appendChild(resourceDetailEle);        
        
        rootEle.appendChild(cacheResourceEle);
        
        // NodeList
        Element cacheNodeListEle = doc.createElement("Cache:NodeList");
        
        int cacheNodeLoop = 0;
        PeerNode cacheNode = null;
        
        while (cacheNodeLoop < this.nodeList.size()) {
            Element cacheNodeEle = doc.createElement("Cache:NodeList:Node");
            cacheNode = (PeerNode) this.nodeList.get(cacheNodeLoop);
            
            // ID
            Element cacheNodeIDEle = doc.createElement("Cache:NodeList:Node:ID");
            Text cacheNodeIDText = doc.createTextNode(cacheNode.getNodeID());
            cacheNodeIDEle.appendChild(cacheNodeIDText);
            cacheNodeEle.appendChild(cacheNodeIDEle);        

            // Type
            Element cacheNodeIPaddressEle = doc.createElement("Cache:NodeList:Node:IPaddress");
            Text cacheNodeIPaddressText = doc.createTextNode(cacheNode.getNodeIPaddress());
            cacheNodeIPaddressEle.appendChild(cacheNodeIPaddressText);
            cacheNodeEle.appendChild(cacheNodeIPaddressEle);        

            // Detail
            Element cacheNodePortEle = doc.createElement("Cache:NodeList:Node:Port");
            Text cacheNodePortText = doc.createTextNode(Integer.toString(cacheNode.getNodePort()));
            cacheNodePortEle.appendChild(cacheNodePortText);
            cacheNodeEle.appendChild(cacheNodePortEle);        
            
            cacheNodeListEle.appendChild(cacheNodeEle);
            cacheNodeLoop++;
        }
        
        rootEle.appendChild(cacheNodeListEle);        
        
        doc.appendChild(rootEle);                
        
        return doc;
    }    
    
    public String toXMLString() throws Exception {
        String result = null;
        
        XMLTools xt = new XMLTools();                
        result = xt.writeXMLString(this.toXMLDoc());
        
        return result;
    }
    
    public void toXMLFile(String fileName) throws Exception {
        // Prepare the DOM document for writing
        Source source = new DOMSource(this.toXMLDoc());

        // Prepare the output file
        File file = new File(fileName);
        Result result = new StreamResult(file);

        // Write the DOM document to the file
        Transformer xformer = TransformerFactory.newInstance().newTransformer();
        xformer.transform(source, result);
    }
    
    public Cache fromXMLDoc(Document dom) {
        Cache result = new Cache();
        
        Element rootEle = dom.getDocumentElement();
        
        if (rootEle.getTagName().equals("Cache")) {
            // Resource
            NodeList cacheResourceList = rootEle.getElementsByTagName("Cache:Resource");
            
            Resource cacheResource = new Resource();

            NodeList resourceIDList = rootEle.getElementsByTagName("Cache:Resource:ID");
            String resourceIDText = resourceIDList.item(0).getFirstChild().getNodeValue();
            NodeList resourceTypeList = rootEle.getElementsByTagName("Cache:Resource:Type");
            String resourceTypeText = resourceTypeList.item(0).getFirstChild().getNodeValue();
            NodeList resourceDetailList = rootEle.getElementsByTagName("Cache:Resource:Detail");
            String resourceDetailText = resourceDetailList.item(0).getFirstChild().getNodeValue();
            cacheResource.setResourceID(resourceIDText);
            cacheResource.setResourceType(resourceTypeText);
            cacheResource.setResourceDetail(resourceDetailText);
            result.setResource(cacheResource);
            
            // NodeList
            NodeList cacheNodeListList = rootEle.getElementsByTagName("Cache:NodeList");
            NodeList cacheNodeList = rootEle.getElementsByTagName("Cache:NodeList:Node");

            int cacheNodeLoop = 0;
            while (cacheNodeLoop < cacheNodeList.getLength()) {
                NodeList nodeListEle = cacheNodeList.item(cacheNodeLoop).getChildNodes();
                
                PeerNode cacheNode = new PeerNode();
                
                String nodeIDText = nodeListEle.item(0).getFirstChild().getNodeValue();
                String nodeIPaddressText = nodeListEle.item(1).getFirstChild().getNodeValue();
                String nodePortText = nodeListEle.item(2).getFirstChild().getNodeValue();

                cacheNode.setNodeID(nodeIDText);
                cacheNode.setNodeIPaddress(nodeIPaddressText);
                cacheNode.setNodePort(Integer.valueOf(nodePortText));

                result.addNode(cacheNode);

                cacheNodeLoop++;
            }
        }
                
        return result;
    }
    
    public Cache fromXMLString(String data) throws Exception {
        Document dom = null;
        XMLTools xt = new XMLTools();
        Cache result = null;
        
        // Parse the XML stream input to Document type
        dom = xt.db.parse(new InputSource(new StringReader(data)));
        
        result = fromXMLDoc(dom);
        
        return result;
    }
    
    public Cache fromXMLFile(String fileName) throws Exception {
        Document dom = null;
        File file = null;
        Cache result = null;
        XMLTools xt = new XMLTools();
        
        // Parse the XML stream input to Document type
        file = new File(fileName);
        dom = xt.db.parse(file);
        
        result = fromXMLDoc(dom);
        
        return result;
    }
    
//    public static void main(String[] args) throws Exception {
//        Node n1 = new Node("192.168.0.1", 9090);
//        Node n2 = new Node("192.168.0.2", 9090);
//        Node n3 = new Node("192.168.0.3", 9090);
//        
//        Resource r1 = new Resource();
//        r1 = r1.fromXMLFile("r1.xml");
//        
//        Cache c1 = new Cache();
//        c1.setResource(r1);
//        c1.addNode(n1);
//        c1.addNode(n2);
//        c1.addNode(n3);
//        System.out.println(c1.toXMLString());
//        c1.toXMLFile("c1.xml");
//
//        Cache c2 = new Cache();
//        c2 = c2.fromXMLFile("c1.xml");
//        c2.toXMLFile("c2.xml");
//    }
}
